import os
from flask import Flask, request, g, jsonify, current_app
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from backend.config import Config
from backend.models import db, User
from backend.routes.auth import auth_bp
from backend.routes.properties import properties_bp
from backend.routes.footprints import footprints_bp
from backend.routes.users import users_bp
from flask_jwt_extended import JWTManager, verify_jwt_in_request, get_jwt, get_jwt_identity, exceptions as jwt_exceptions
from flask_cors import CORS
import logging

from backend.utils import api_response


# --- Rate Limiter Key Function (保持不变或根据上一轮建议修改) ---
def limiter_key_func():
    """根据认证状态和来源IP/标识生成限速器Key"""
    # 1. 优先检查 JWT 认证
    try:
        verify_jwt_in_request(optional=True, locations=['cookies', 'headers'])
        jwt_claims = get_jwt()
        if jwt_claims:
            user_id = jwt_claims.get('sub')
            role = jwt_claims.get('role')
            if role == 'admin':
                return f"jwt-admin-{user_id}" # 管理员的特殊 key
            return f"jwt-user-{user_id}"    # 其他JWT用户的 key
    except jwt_exceptions.NoAuthorizationError:
        pass # 没有 JWT，继续检查 API Key
    except Exception as e:
        # 降低日志级别，避免在 JWT 无效或过期时产生过多错误日志
        current_app.logger.debug(f"JWT verification attempt for rate limiting key_func (non-fatal): {e}", exc_info=False)
        pass

    # 2. 检查 API Key (仅在无有效JWT时检查)
    apikey_value = request.args.get('apikey') or request.headers.get('X-API-KEY')
    if apikey_value:
        # 对于 API Key 用户，可以使用 API Key 本身
        return f"apikey-user-{apikey_value}"

    # 3. 匿名用户
    return f"anonymous-{get_remote_address()}"


# --- 新增：请求豁免过滤器 ---
def not_anonymous_request_filter():
    """
    检查当前请求是否为非匿名请求 (即，拥有有效的JWT或提供了API Key)。
    返回 True 表示“不是纯匿名的”，应豁免最严格的匿名限制。
    返回 False 表示“是纯匿名的”，不应豁免，应应用最严格的限制。
    """
    # 1. 检查 JWT
    try:
        verify_jwt_in_request(optional=True, locations=['cookies', 'headers'])
        if get_jwt(): # 如果有 JWT，则不是匿名 -> 应该豁免
            return True
    except Exception:
        # JWT 检查异常，继续判断 API Key
        pass

    # 2. 检查 API Key
    if request.args.get('apikey') or request.headers.get('X-API-KEY'):
        # 如果有 API Key，则不是匿名 -> 应该豁免
        return True

    # 3. 既无 JWT 也无 API Key，则是纯匿名 (不应豁免)
    return False


def create_app():

    # 创建纯API应用实例（移除前端模板配置）
    app = Flask(__name__)

    # 加载配置
    app.config.from_object(Config)
    app.config['WTF_CSRF_ENABLED'] = False  # 彻底关闭 CSRF


    # 配置日志
    logging.basicConfig(level=logging.INFO)
    if not app.debug:
        # 生产环境可以配置更复杂的日志记录，例如输出到文件
        pass

    # --- 初始化 Limiter ---
    limiter = Limiter(
        key_func=limiter_key_func,
        # default_limits 是 JWT 用户和 API Key 用户的默认限制
        # (除非有更具体的规则覆盖他们，或者他们被豁免了更严格的规则)
        default_limits=["200 per hour", "50 per minute"], # 例如：管理员和API Key用户
        storage_uri="memory://", # 开发用; 生产建议用 "redis://localhost:6379"
        strategy="fixed-window",
    )
    limiter.init_app(app)

    # --- 注册全局限速错误处理器 (使用 utils.api_response) ---
    @app.errorhandler(429)
    def ratelimit_handler(e):
        # 直接调用 api_response 函数，它会返回 jsonify 的结果和状态码
        return api_response(code=429, message=f"触发限速: {e.description}")

    # 配置JWT（新增详细配置）
    jwt = JWTManager(app)
    # 添加以下配置（取消原注释配置）：
    app.config.update({
        'JWT_COOKIE_SECURE': True,  # 仅HTTPS传输
        'JWT_COOKIE_SAMESITE': 'Lax',  # 防止CSRF攻击
        'JWT_ACCESS_TOKEN_EXPIRES': 3600,  # 1小时有效期
        'JWT_TOKEN_LOCATION': ['cookies', 'headers'],  # 支持cookie和header两种方式
        'JWT_COOKIE_CSRF_PROTECT': False
    })

    # 添加用户身份验证回调（在JWT配置下方添加）
    @jwt.user_lookup_loader
    def user_lookup_callback(_jwt_header, jwt_data):
        """每次请求自动验证JWT对应的用户是否存在"""
        user_id = jwt_data["sub"]
        return User.query.get(user_id)

    # 初始化数据库
    db.init_app(app)
    with app.app_context():
        db.create_all()  # 自动创建数据表（如果不存在）


    # 强化CORS配置（生产环境应指定具体域名）
    from flask_cors import CORS
    CORS(app,
         resources={
             r"/api/*": {
                 "origins": "http://localhost:5173",
                 "supports_credentials": True,
                 "allow_headers": ["Authorization", "Content-Type", "X-API-KEY"],
                 "methods": ["GET", "POST", "PUT", "DELETE","OPTIONS"]
             },
             r"/auth/*": {
                 "origins": "http://localhost:5173",
                 "supports_credentials": True,
                 "allow_headers": ["Authorization", "Content-Type", "X-API-KEY"],
                 "methods": ["POST"]
             }
         },
         supports_credentials=True)


    # 组织API路由（符合RESTful规范）
    # 认证相关路由
    app.register_blueprint(auth_bp, url_prefix='/api/auth')
    app.register_blueprint(properties_bp, url_prefix='/api/properties')
    app.register_blueprint(footprints_bp, url_prefix='/api/footprints')
    # 注册用户管理路由
    app.register_blueprint(users_bp, url_prefix='/api/users')

    # --- 应用特定的 Rate Limits ---

    # 1. 对 POI 蓝图的 GET 请求应用最严格限速，但豁免非匿名用户 (即JWT或API Key用户)
    limiter.limit(
        "60 per hour;10 per minute",  # 纯匿名用户的严格限制
        methods=['GET'],
        # 使用 exempt_when，当 not_anonymous_request_filter() 返回 True 时豁免此规则
        exempt_when=not_anonymous_request_filter
    )(properties_bp)

    # 2. 登录/注册接口 (这些通常是匿名的，其 key 会是 anonymous-<ip>)
    # 如果匿名用户访问这些接口，他们会受到上面的 "10 per minute" POI GET 限制（如果路径匹配）
    # 或者这里的 "20 per minute" POST 限制。Flask-Limiter 会选择最严格的那个。
    # 为了更清晰，可以为 auth_bp 的匿名访问设置一个独立的 key，或者接受这种行为。
    limiter.limit("20 per minute;200 per hour", methods=['POST'])(auth_bp)

    # (可选) 为管理员角色设置更高的特定限制 (如果 key_func 返回了 jwt-admin-...)
    # 这会覆盖 jwt-admin-* key 的 default_limits
    #limiter.limit("500 per hour;100 per minute", for_keys_matching=lambda k: k.startswith("jwt-admin-"))(app)

    # 统一错误处理
    @app.errorhandler(404)
    def not_found(error):
        return {
            "code": 404,
            "message": "Resource not found",
            "error": str(error)
        }, 404

    @app.errorhandler(429)
    def ratelimit_handler(error):
        return {
            "code": 429,
            "message": "Too many requests",
            "error": f"Request limit exceeded: {error.description}"
        }, 429

    @app.errorhandler(500)
    def internal_error(error):
         # 记录原始错误
         app.logger.error(f"Internal Server Error: {error}", exc_info=True)
         return api_response(code=500, message="服务器内部错误")

    app.logger.info("Flask App Created Successfully")
    return app


# 运行应用（新增生产环境配置提示）
if __name__ == '__main__':
    app = create_app()
    # 生产环境应使用以下配置
    app.run(host='0.0.0.0', port=5000, debug=False)










